package org.zero.controller;

import java.nio.file.AccessDeniedException;
import java.sql.SQLException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.zero.model.R;

/**
 * @author Zero (cnzeropro@qq.com)
 * @date 2021/9/2 12:17
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ResponseStatus(HttpStatus.FORBIDDEN)
    @ExceptionHandler(AccessDeniedException.class)
    public R<Object> exception(AccessDeniedException e) {
        log.error("无权访问", e);
        return R.builder()
                .code(403)
                .errorMessage("A0300")
                .errorMessage(e.getMessage())
                .message("无权访问" + e.getReason())
                .build();
    }

    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NoHandlerFoundException.class)
    public R<Object> notFound(NoHandlerFoundException e) {
        log.warn("请求路径未找到", e);

        return R.builder()
                .code(404)
                .errorCode("B0001")
                .errorMessage(e.getMessage())
                .message("请求路径【" + e.getRequestURL() + "】未找到")
                .build();
    }

    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public R<Object> methodNotSupported(HttpRequestMethodNotSupportedException e) {
        log.warn("请求方式有误", e);
        return R.builder()
                .code(405)
                .errorMessage("B0001")
                .errorMessage(e.getMessage())
                .message(e.getMethod() + "请求方式有误，正确请求方法为：" + e.getSupportedHttpMethods())
                .build();
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.warn("参数验证错误", e);
        return R.builder()
                .code(500)
                .errorMessage("B0001")
                .errorMessage(e.getMessage())
                .message("参数验证错误：" + e.getParameter().getParameterName())
                .build();
    }

    @ExceptionHandler(TypeMismatchException.class)
    public R<Object> requestTypeMismatch(TypeMismatchException e) {
        log.warn("参数类型不一致", e);
        return R.builder()
                .code(500)
                .errorMessage(e.getMessage())
                .message("参数类型不匹配，参数" + e.getPropertyName() + "类型应该为" + e.getRequiredType())
                .build();
    }

    @ExceptionHandler(MultipartException.class)
    public R<Object> fileSizeLimit(MultipartException e) {
        log.warn("超过文件上传大小限制", e);
        return R.builder()
                .code(500)
                .errorMessage(e.getMessage())
                .message("超过文件大小限制，最大10MB")
                .build();
    }

    @ExceptionHandler(SQLException.class)
    public R<Object> sqlException(SQLException e) {
        log.error("SQL 异常", e);
        return R.builder()
                .code(500)
                .errorMessage(e.getMessage())
                .message("SQL 异常")
                .build();
    }

    @ExceptionHandler(BindException.class)
    public R<Object> bindException(BindException e) {
        log.error("参数绑定错误", e);
        return R.builder()
                .code(500)
                .errorMessage(e.getMessage())
                .message("参数绑定错误，请检查参数类型或格式是否正确")
                .build();
    }

    @ExceptionHandler(Exception.class)
    public R<Object> exception(Exception e) {
        log.error("系统未知错误", e);
        return R.builder()
                .code(500)
                .errorMessage(e.getMessage())
                .message("系统发生未知错误，请稍后重试")
                .build();
    }
}
